package nl.tue.be.ds.duraark.bSDD.dump;

import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.ws.rs.core.MediaType;

import nl.tue.be.ds.duraark.bSDD.ClientUtilities;
import nl.tue.be.ds.duraark.bSDD.DataBaseUtilities;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;


public class ConSearchPerTermPatternCallable implements Callable<Integer> {
	
	private String searchTerm;
	private boolean isTaskTooMany;
	private final int MaxRecursionDep = 2;
	private final String conceptSearchUrl = "http://bsddpilot.catenda.no/api/4.0/IfdConcept/search/";

	
	
	public ConSearchPerTermPatternCallable(String searchTerm, boolean isTaskTooMany) {
		this.searchTerm = searchTerm;
		this.isTaskTooMany = isTaskTooMany;
	}

	public Integer call() throws Exception {
		Integer conceptCounter = 0;
		if (!isTaskTooMany){
			conceptCounter = new Integer(dumpPerTermPattern(searchByMoreTask()));
		}else{
			conceptCounter = new Integer(dumpPerTermPattern(searchByRecursion()));
		}
		
		DataBaseUtilities.db.commit();
		return conceptCounter;
	}
	
/*	private Integer dumpPerTermPattern(JsonNode jsonConcepts){
		Integer i = 1;
		
		DumpProcessor.jsonConceptsList.add(jsonConcepts);
		//DumpProcessor.processDumpBySearchCallable();
		
		return i;
	}*/
	
	private Integer dumpPerTermPattern(JsonNode jsonConcepts){
		Integer i = 0;
		
		StorageUnitDumpCallable dsu = new StorageUnitDumpCallable(jsonConcepts);		
		ExecutorService threadPool = Executors.newSingleThreadExecutor();
		Future<Integer> f = threadPool.submit(dsu);
		
		try {
				i = f.get();
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		} catch (ExecutionException e) {
			
			e.printStackTrace();
		}
		
		threadPool.shutdown(); 
		
		return i;
		
	}
	
	
	private JsonNode searchByMoreTask() throws Exception{
		String res = null;
		JsonNode jsonConcepts;
		Client client = ClientUtilities.getClient();

		WebResource searchCall = client.resource(conceptSearchUrl + searchTerm + "*");
		
		try{
			res = searchCall.accept(MediaType.APPLICATION_JSON_TYPE).cookie(ClientUtilities.cookie).get(String.class);
		}catch(Exception e){
			if (e instanceof UniformInterfaceException){
				throw new Exception(searchTerm, e);
			}else{
				e.printStackTrace();
			}
		}
	
		if (res != null) {
			ObjectMapper mapper = ClientUtilities.getMapper();
			JsonNode root = mapper.readTree(res);
			jsonConcepts = root.get("IfdConcept");
		} else {
			jsonConcepts = null;
		}
		return jsonConcepts;
		
	}
	
	
	private JsonNode searchByRecursion() throws Exception{
		Integer recursionDep = 0;
		Client client = ClientUtilities.getClient();
		JsonNode jsonConcepts = getPatternSearch(searchTerm, client, recursionDep);
		return jsonConcepts;
	}
	
	private JsonNode getPatternSearch(String searchTerm, Client client, Integer recursionDep){
		JsonNode jsonConcepts = null;
		
		recursionDep++;
		if ((searchTerm.length()<= ConSearchProcessor.MaxSearchTermLength)){
			WebResource searchCall = client.resource(conceptSearchUrl + searchTerm + "*");
			try {
				String res = searchCall.accept(MediaType.APPLICATION_JSON_TYPE).cookie(ClientUtilities.cookie).get(String.class);
				jsonConcepts = getJsonConcepts(res);
			} catch (Exception e) {
				if (e instanceof UniformInterfaceException) {
					jsonConcepts = mergeJsonConcepts(jsonConcepts, getTermSearch(searchTerm, client));
					for (char ch = 'a'; ch <= 'z'; ch++) {
						String newSearchTerm = searchTerm + Character.toString(ch);
						if (recursionDep <= MaxRecursionDep){
							jsonConcepts = mergeJsonConcepts(jsonConcepts, getPatternSearch(newSearchTerm, client, recursionDep));
						}else{
							if (newSearchTerm.length()<=ConSearchProcessor.MaxSearchTermLength){
								ConSearchProcessor.futureList.add(ConSearchProcessor.postSearchCallPerTermPattern(newSearchTerm, ConSearchProcessor.isTaskTooMany()));
							}
						}
					}
				} else {
					e.printStackTrace();
				}
			}
		}
		return jsonConcepts;
	}
	
	private JsonNode getTermSearch(String searchTerm, Client client){
		JsonNode jsonConcepts = null;
		WebResource searchCall = client.resource(conceptSearchUrl + searchTerm);
		try{
			String res = searchCall.accept(MediaType.APPLICATION_JSON_TYPE).cookie(ClientUtilities.cookie).get(String.class);
			jsonConcepts = getJsonConcepts(res);
		}catch(Exception e){
			if (e instanceof UniformInterfaceException){
				jsonConcepts = getTermSearch(searchTerm, client);
			}else{
				e.printStackTrace();
			}
		}
		
		return jsonConcepts;
		
	}
	
	private JsonNode mergeJsonConcepts(JsonNode jConcepts1, JsonNode jConcepts2){
		ObjectMapper mapper = ClientUtilities.getMapper();
		ArrayNode tmpArrayNode = mapper.createArrayNode();
		
		if ((jConcepts1 != null) && (jConcepts2 != null)) {

			if (jConcepts1.isObject()) {
				if (jConcepts2.isObject()) {
					tmpArrayNode.add(jConcepts1);
					tmpArrayNode.add(jConcepts2);
				} else {
					tmpArrayNode.add(jConcepts1);
					Iterator<JsonNode> itr = jConcepts2.iterator();
					while (itr.hasNext()) {
						tmpArrayNode.add((JsonNode) itr.next());
					}
				}
			} else {
				if (jConcepts2.isObject()) {
					tmpArrayNode.add(jConcepts2);
					Iterator<JsonNode> itr = jConcepts1.iterator();
					while (itr.hasNext()) {
						tmpArrayNode.add((JsonNode) itr.next());
					}
				} else {
					Iterator<JsonNode> itr = jConcepts1.iterator();
					while (itr.hasNext()) {
						tmpArrayNode.add((JsonNode) itr.next());
					}
					itr = jConcepts2.iterator();
					while (itr.hasNext()) {
						tmpArrayNode.add((JsonNode) itr.next());
					}
				}
			}
		}else if ((jConcepts1 != null) && (jConcepts2 == null)){
			tmpArrayNode = (ArrayNode) jConcepts1;
		}else if ((jConcepts1 == null) && (jConcepts2 != null)){
			tmpArrayNode = (ArrayNode) jConcepts2;
		}
		
		return tmpArrayNode;
	}
	
	private JsonNode getJsonConcepts(String res) throws JsonProcessingException, IOException{
		JsonNode jsonConcepts;
		if (res != null) {
			ObjectMapper mapper = ClientUtilities.getMapper();
			JsonNode root = mapper.readTree(res);
			jsonConcepts = root.get("IfdConcept");
		} else {
			jsonConcepts = null;
		}
		return jsonConcepts;	
	}
	
}
